package service

import (
	"blizzard/app/dao"
	"blizzard/app/model"
	"blizzard/app/utils/code"
	"blizzard/app/utils/tool"
	"github.com/gogf/gf/errors/gerror"
	"github.com/gogf/gf/frame/g"
	"github.com/gogf/gf/net/ghttp"
	"github.com/gogf/gf/util/gconv"
)

var User = new(serviceUser)

type serviceUser struct {}

func (s *serviceUser) Register(r *ghttp.Request, id int, m *model.UserRegisterParam) error {
	var (
		err error
	)
	if tool.GetTime() + 100 < m.Time || tool.GetTime() - 100 > m.Time {
		return gerror.New(code.RequestExpired)
	}
	if err = dao.BxBlack.IsBlackMachine(m.MachineCode); err != nil {
		return err
	}
	one, err := dao.BxSoftware.FindOne("id = ?", id)
	if err != nil {
		return gerror.New(code.SoftwareErrorMsg)
	}
	restrictTime := tool.GetTime() - (one.RestrictRegtime * 60 * 60)
	restrict, err := dao.BxUser.Statistics(m.MachineCode, restrictTime, id)
	if err != nil {
		return gerror.New(code.ParamErrorMsg)
	}
	if restrict >= one.RestrictRegnum {
		return gerror.New(code.RegisterMaxError)
	}
	_, err = dao.BxUser.IsUser(id, m.Username)
	if err != nil {
		return err
	}
	user := make(map[string]interface{})
	user["username"] = m.Username
	user["machine_code"] = m.MachineCode
	user["regtime"] = tool.GetTimeString()
	user["regip"] = r.GetClientIp()
	user["software_id"] = id
	user["menber_id"] = m.Uid
	user["salt"] = tool.RndString(6)
	user["password"] = tool.Md5String(m.Password + gconv.String(user["salt"]))
	user["super_password"] = tool.Md5String(m.SuperPassword + gconv.String(user["salt"]))
	if one.GiveTime > 0 {
		user["endtime"] = (one.GiveTime * 60) + tool.GetTime()
	} else {
		user["endtime"] = 0
	}
	_, err = dao.BxUser.Save(user)
	if err != nil {
		return err
	}
	return nil
}

func (s *serviceUser) Recharge(id int, m *model.UserRechargeParam) (err error, mk interface{}) {
	if tool.GetTime() + 100 < m.Time || tool.GetTime() - 100 > m.Time {
		return gerror.New(code.RequestExpired), nil
	}
	res := make(map[string]interface{})
	one, err := dao.BxUser.IsUser(id, m.Username)
	if err != nil {
		return err, nil
	}
	if one == nil {
		return gerror.New(code.AccountErrorMsg), nil
	}
	cardRes, err := dao.BxCard.FindOne(
		"cardnum = ? AND software_id = ?",
		m.RechargeCard, id)
	if err != nil {
		return err, nil
	}
	if cardRes == nil {
		return gerror.New(code.CardError), nil
	}
	if cardRes.State == 2 {
		return gerror.New("充值卡:" + m.RechargeCard + " 停止使用"), nil
	}
	if cardRes.Used == 2 {
		return gerror.New("充值卡:" + m.RechargeCard + " 已被使用"), nil
	}
	time := tool.GetCardType(cardRes.Time, cardRes.TimeType)
	if gconv.Int(one.Endtime) >= tool.GetTime() {
		num := gconv.Int(one.Endtime) + time
		one.Endtime = gconv.String(num)
	} else {
		num := tool.GetTime() + time
		one.Endtime = gconv.String(num)
	}
	_, err = dao.BxUser.Save(one)
	if err != nil {
		return err, nil
	}
	_, err = dao.BxCard.Data(g.Map{
		"used": 2,
	}).Where("cardnum = ?", m.RechargeCard).Update()
	if err != nil {
		return err, nil
	}
	res["endtime"] = one.Endtime
	res["time"] = cardRes.Time
	res["time_type"] = cardRes.TimeType
	return nil, res
}

func (s *serviceUser) PassChange(id int, m *model.UserPassChangeParam) (di interface{},err error) {
	if tool.GetTime() + 100 < m.Time || tool.GetTime() - 100 > m.Time {
		return nil, gerror.New(code.RequestExpired)
	}
	user, err := dao.BxUser.IsUser(id, m.Username)
	if err != nil {
		return nil, gerror.New(code.AccountErrorMsg)
	}
	if user.SuperPassword != tool.Md5String(m.SuperPassword + user.Salt) {
		return nil, gerror.New("超级密码错误")
	}
	user.Salt = tool.RndString(6)
	user.Password = tool.Md5String(m.Password + user.Salt)
	user.SuperPassword = tool.Md5String(user.SuperPassword + user.Salt)
	_, err = dao.BxUser.Save(user)
	if err != nil {
		return nil, err
	}
	res := make(map[string]interface{})
	res["new"] = m.Password
	return res, nil
}

func (s *serviceUser) Login(r *ghttp.Request, id int, m *model.UserLoginParam) (data interface{},err error) {
	mast := make(map[string]interface{})
	if tool.GetTime() + 100 < m.Time || tool.GetTime() - 100 > m.Time {
		return nil, gerror.New(code.RequestExpired)
	}
	one, err := dao.BxSoftware.FindOne("id = ?", id)
	if err != nil {
		return nil, gerror.New(code.SoftwareErrorMsg)
	}
	if err = dao.BxBlack.IsBlackMachine(m.MachineCode); err != nil {
		return nil, err
	}
	userRes, err := dao.BxUser.IsUser(id, m.Username)
	if err != nil {
		return nil, gerror.New(code.AccountErrorMsg)
	}
	if userRes.Password != tool.Md5String(m.Password + userRes.Salt) {
		return nil, gerror.New(code.AccountErrorMsg)
	}
	if userRes.Congeal == 2 {
		return nil, gerror.New(code.AccountSeal)
	}
	if one.BindingType == 2 {
		if userRes.MachineCode != m.MachineCode {
			return nil, gerror.New(code.SoftwareMachineError)
		}
	}
	if one.SoftwareState != 3 {
		if gconv.Int(userRes.Endtime) <= tool.GetTime() {
			return nil, gerror.New(code.UserExpireMsg)
		}
	}
	if userRes.State == 2 {
		if gconv.Int(userRes.HeartBeat) >= tool.GetTime() {
			if one.LoginType == 2 && userRes.MachineCode != m.MachineCode {
				return nil, gerror.New("该用户在线中, 不可登录")
			}
		}
	}
	tk := tool.GetToken(one.SKey, m.Username, m.Password, id)
	userRes.Token = tk
	userRes.State = 2
	userRes.MachineCode = m.MachineCode
	userRes.Logtime = tool.GetTimeString()
	userRes.Logip = r.GetClientIp()
	userRes.HeartBeat = gconv.String(tool.GetTime() + gconv.Int(one.HeartTime))
	_, err = dao.BxUser.Save(userRes)
	if err != nil {
		return nil, err
	}
	mast["endtime"] = userRes.Endtime
	mast["token"] = tk
	return mast, nil
}

func (s *serviceUser) Logout(m *model.UserLogoutParam) error {
	if tool.GetTime() + 100 < m.Time || tool.GetTime() - 100 > m.Time {
		return gerror.New(code.RequestExpired)
	}
	data, err := dao.BxUser.FindOne("username = ?", m.Username)
	if err != nil {
		return gerror.New(code.AccountErrorMsg)
	}
	if data.Password != tool.Md5String(m.Password + data.Salt) {
		return gerror.New(code.AccountErrorMsg)
	}
	token := tool.ParseToken(m.Token, m.AppKey)
	err = token.Valid()
	if err != nil {
		return err
	}
	data.State = 1
	data.HeartBeat = gconv.String(gconv.Int(tool.GetTime() - 10))
	_, err = dao.BxUser.Save(data)
	if err != nil {
		return err
	}
	return nil
}

func (s *serviceUser) UnBind(id int, m *model.UserUnbindParam) (n interface{},err error) {
	var (
		user *model.BxUser
		one *model.BxSoftware
	)
	if tool.GetTime() + 100 < m.Time || tool.GetTime() - 100 > m.Time {
		return nil, gerror.New(code.RequestExpired)
	}
	err = dao.BxBlack.IsBlackMachine(m.MachineCode)
	if err != nil {
		return nil, err
	}
	user, err = dao.BxUser.IsUser(id, m.Username)
	if err != nil {
		return nil, gerror.New(code.AccountErrorMsg)
	}
	if user.Password != tool.Md5String(m.Password + user.Salt) {
		return nil, gerror.New(code.AccountErrorMsg)
	}
	one, err = dao.BxSoftware.FindOne("id = ?", id)
	if err != nil {
		return nil, err
	}
	if one.BindingType != 2 {
		return nil, gerror.New(code.SoftwareMachine)
	}
	if user.MachineCode == m.MachineCode {
		return nil, gerror.New(code.SoftwareCodeError)
	}
	if one.BindingdelType == 2 {
		return nil, gerror.New(code.SoftwareCantUnbind)
	}
	if one.BindingdelTime > 0 {
		if gconv.Int(user.Endtime) - (one.BindingdelTime * 60) > tool.GetTime() {
			user.Endtime = gconv.String(gconv.Int(user.Endtime) - (one.BindingdelTime *60))
		} else {
			return nil, gerror.New("用户所剩时间不够扣除!")
		}
	}
	user.MachineCode = ""
	_, err = dao.BxUser.Save(user)
	if err != nil {
		return nil, err
	}
	data := g.Map{}
	data["unbind_time"] = one.BindingdelTime
	return data, nil
}

func (s *serviceUser) Trial(id int, m *model.UserTrialParam) (interface{}, error) {
	var (
		user *model.BxUser
		app *model.BxSoftware
		err error
	)
	if tool.GetTime() + 100 < m.Time || tool.GetTime() - 100 > m.Time {
		return nil, gerror.New(code.RequestExpired)
	}
	user, err = dao.BxUser.IsUser(id, m.Username)
	if err != nil {
		return nil, err
	}
	if user.Password != tool.Md5String(m.Password + user.Salt) {
		return nil, err
	}
	app, err = dao.BxSoftware.FindOne("id = ?", id)
	if err != nil {
		return nil, err
	}
	if app.TrialInterval <= 0 || app.TrialData <= 0 {
		return nil, gerror.New(code.SoftwareNoTrial)
	}
	if (tool.GetTime() - gconv.Int(user.Trial)) < (app.TrialInterval * 3600) {
		return nil, gerror.New("用户距离上次试用还不到:" +
			gconv.String(app.TrialInterval) + " 小时!")
	}
	if gconv.Int(user.Endtime) > tool.GetTime() {
		return nil, gerror.New(code.UserExpireMsg)
	}
	user.Trial = gconv.String(tool.GetTime())
	user.Endtime = gconv.String(tool.GetTime() + (app.TrialData * 60))
	_, err = dao.BxUser.Save(user)
	if err != nil {
		return nil, err
	}
	data := g.Map{}
	data["trial_data"] = app.TrialData
	return data, nil
}

func (s *serviceUser) Heart(id int, m *model.UserHeartParam) error {
	var (
		app  *model.BxSoftware
		user *model.BxUser
		err  error
	)
	if tool.GetTime() + 100 < m.Time || tool.GetTime() - 100 > m.Time {
		return gerror.New(code.RequestExpired)
	}
	user, err = dao.BxUser.IsUser(id, m.Username)
	if err != nil {
		return err
	}
	if user.Password != tool.Md5String(m.Password+user.Salt) {
		return gerror.New(code.AccountErrorMsg)
	}
	token := tool.ParseToken(m.Token, m.AppKey)
	err = token.Valid()
	if err != nil {
		return err
	}
	app, err = dao.BxSoftware.FindOne("id = ?", id)
	if err != nil {
		return gerror.New(code.SoftwareErrorMsg)
	}
	if app.SoftwareState != 3 {
		if gconv.Int(user.Endtime) < tool.GetTime() {
			return gerror.New(code.UserExpireMsg)
		}
	}
	if user.State == 1 {
		return gerror.New(code.UserForced)
	}
	user.HeartBeat = gconv.String(tool.GetTime() + app.HeartTime)
	_, err = dao.BxUser.Save(user)
	if err != nil {
		return err
	}
	return nil
}

func (s *serviceUser) GetUserData(id int, m *model.GetUserDataParam) (interface{}, error) {
	if tool.GetTime() + 100 < m.Time || tool.GetTime() - 100 > m.Time {
		return nil, gerror.New(code.RequestExpired)
	}
	user, err := dao.BxUser.IsUser(id, m.Username)
	if err != nil {
		return nil, err
	}
	if user.Password != tool.Md5String(m.Password + user.Salt) {
		return nil, gerror.New(code.AccountErrorMsg)
	}
	data := g.Map{}
	data["user_data"] = user.UserData
	return data, nil
}

func (s *serviceUser) SetUserData(id int, m *model.SetUserDataParam) error {
	if tool.GetTime() + 100 < m.Time || tool.GetTime() - 100 > m.Time {
		return gerror.New(code.RequestExpired)
	}
	user, err := dao.BxUser.IsUser(id, m.Username)
	if err != nil {
		return err
	}
	if user.Password != tool.Md5String(m.Password + user.Salt) {
		return gerror.New(code.AccountErrorMsg)
	}
	user.UserData = m.UserData
	_, err = dao.BxUser.Save(user)
	if err != nil {
		return err
	}
	return nil
}

func (s *serviceUser) QueryCard(m *model.QueryCardParam) (interface{}, error) {
	if tool.GetTime() + 100 < m.Time || tool.GetTime() - 100 > m.Time {
		return nil, gerror.New(code.RequestExpired)
	}
	one, err := dao.BxCard.FindOne("card = ?", m.Card)
	if err != nil {
		return nil, err
	}
	data := g.Map{}
	data["name"] = one.Name
	data["time"] = one.Time
	data["time_type"] = one.TimeType
	data["create_time"] = one.CreateTime
	data["state"] = one.State
	data["used"] = one.Used
	return data, nil
}